package com.jwd.comm

import java.util.ArrayList
import java.util.HashMap

/**
 * Created by jin on 2017/3/10.
 */
open class MapModel() : HashMap<String, Any>() {

    override   fun get(key: String): String {
        return super.get(key).toString()
    }

    fun add(other: MapModel?) {
        if (other == null) return

        for (key in other.keys) {
            this.put(key, other[key]!!)
        }
    }

    /**
     * 如果对象不存在该层级，则进行创建。

     * @param KeyPath  层级形式： a[0][0][0].Id
     * *
     * @param SetValue
     */
    private fun tourch(KeyPath: String, SetValue: String): Any? {
        if (this.containsKey(KeyPath)) return null

        val sepIndex = KeyPath.GetIndexChar_SkipInQuote( 0, '.', '[')
        if (sepIndex < 0) {
            this.put(KeyPath, SetValue)
            return SetValue
        }

        val chr = KeyPath[sepIndex]

        val objKey = KeyPath.substring(0, sepIndex)

        if (chr == '.') {
            if (this.containsKey(objKey) == false) {
                this.put(objKey, MapModel())
            }

            val vv = MapModel.castFrom(this[objKey] as HashMap<Any, Any>)
            return vv!!.tourch(KeyPath.substring(sepIndex + 1), SetValue)
        } else {
            if (this.containsKey(objKey) == false) {
                this.put(objKey, ArrayList<Any>())
            }

            val list = this[objKey] as MutableList<Any?>

            var nextDotIndex = KeyPath.indexOf('.', sepIndex + 1)
            if (nextDotIndex < 0) {
                nextDotIndex = KeyPath.length
            }

            val aryIndexs_Strings =   KeyPath.slice(sepIndex..nextDotIndex-1).replace(" ", "").replace("][", ",").TrimWithPair("[", "]").split(',')
            val aryIndexs = ArrayList<Int>()
            for (k in aryIndexs_Strings) {
                aryIndexs.add(  k.toInt() )
            }


            val vv = MapModel.castFrom(patchArrayLevels(list, aryIndexs, SetValue, nextDotIndex > 0, 0) as HashMap<Any, Any>?)

            if (vv != null) {
                return vv.tourch(KeyPath.Slice(  nextDotIndex + 1), SetValue)
            } else {
                return SetValue
            }
        }
    }


    fun findConfigValue(KeyPath: String): Any? {
        if (this.containsKey(KeyPath)) return this[KeyPath]

        val sepIndex = KeyPath.GetIndexChar_SkipInQuote(  0, '.', '[')
        if (sepIndex < 0) {
            return null
        }

        val chr = KeyPath[sepIndex]

        val objKey = KeyPath.substring(0, sepIndex)
        if (this.containsKey(objKey) == false) {
            return null
        }
        if (chr == '.') {
            val vv = MapModel.castFrom(this[objKey]) ?: return null
            return vv.findConfigValue(KeyPath.substring(sepIndex + 1))
        } else {
            val list = this[objKey] as List<Any> ?: return null

            var nextDotIndex = KeyPath.indexOf('.', sepIndex + 1)
            if (nextDotIndex < 0) {
                nextDotIndex = KeyPath.length
            }

            val aryIndexs_Strings =   KeyPath.slice( sepIndex..nextDotIndex -1) .replace(" ", "").replace("][", ",").TrimWithPair( "[", "]").split( ',')
            val aryIndexs = ArrayList<Int>()
            for (k in aryIndexs_Strings) {
                aryIndexs.add(k.toInt())
            }


            val vv = findArrayLevels(list, aryIndexs, 0) ?: return null

            if (nextDotIndex >= KeyPath.length) {
                return vv
            } else {
                val vvm = MapModel.castFrom(vv) ?: return null

                return vvm.findConfigValue(KeyPath.Slice(  nextDotIndex + 1))
            }
        }
    }

    companion object {

        fun loadPair(vararg args: Any): MapModel {
            if (args == null) return MapModel()
            if (args.size % 2 != 0) return MapModel()

            val model = MapModel()
            if (args.size == 0) return MapModel()

            var i = 0
            while (i < args.size) {
                model.put(args[i].toString(), args[i + 1])
                i = i + 2
            }

            return model
        }

        /**
         * 从URL中加载MapModel，做为扩展，允许 Key值带有层级。

         * @param UrlQuery 层级形式： a[0][0][0].Id
         * *
         * @return
         */
        fun loadFromUrl(UrlQuery: String): MapModel {
            val ret = MapModel()

            val list = UrlQuery.split('&')
            for (item in list) {

                val kv = item.split( '=')
                ret.tourch(kv[0], kv[1])
            }

            return ret
        }

        /// <summary>
        /// a[0][0][0].Id = 1 , 则创建3级数组，返回 字典
        /// </summary>
        /// <param name="list"></param>
        /// <param name="indexs"></param>
        /// <param name="Value"></param>
        /// <param name="NextIsDict">下一个对象是否是字典。</param>
        /// <param name="level"></param>
        /// <returns>如果后面是字典，则返回字典，否则返回null</returns>
        private fun patchArrayLevels(list: MutableList<Any?>, indexs: List<Int>, Value: String, NextIsDict: Boolean, level: Int): Any? {
            val index = indexs[level]
            if (level >= indexs.size - 1) {
                if (NextIsDict) {
                    for (i in list.size..index) {
                        list.add(MapModel())
                    }
                    list[index] = MapModel()
                    return list[index]
                } else {
                    for (i in list.size..index) {
                        list.add(null)
                    }
                    list[index] = Value
                    return null
                }
            }


            for (i in list.size..index) {
                list.add(ArrayList<Any>())
            }

            return patchArrayLevels(list[index] as MutableList<Any?>, indexs, Value, NextIsDict, level + 1)
        }

        private fun findArrayLevels(list: List<Any>, indexs: List<Int>, level: Int): Any? {
            val index = indexs[level]
            if (list.size <= index) {
                return null
            }

            if (level >= indexs.size - 1) {
                return list[index]
            }

            return findArrayLevels(list[index] as List<Any>, indexs, level + 1)
        }

        fun castFrom(obj: Any?): MapModel? {
            if (obj == null) return null
            val map = obj as Map<Any, Any>? ?: return null

            val ret = MapModel()

            for (key in map.keys) {
                ret.put(key.toString(), map[key]!!)
            }

            return ret
        }
    }
}